S3 に保存した CloudTrail のログを Athena でクエリして AWS SDK for Java V2 の利用を確認する
こんにちは、岩城です。
ある AWS 環境で AWS SDK for Java V2 を利用しているかを調べる機会がありましたので手順を共有します。
この環境では、CloudTrail の証跡が S3 バケットに保存されていたので、Athena でクエリして UserAgent に aws-sdk-java/2
が含まれているログを抽出することにしました。
ざっくりどうやるの?
本エントリの手順は、CloudTrail の証跡が S3 バケット上に保存されていることを前提にしています。
詳細な手順は後述しますが、ざっくり以下のようなことをします。
- CloudTrail のイベント履歴から Athena に連携してテーブルを作成
- ↑のテーブル作成 DDL を利用して、パーティション分割されたテーブルを再作成
- パーティション分割したテーブルにデータをロード
- AWS SDK for Java V2 の利用がないかクエリ
やってみた
CloudTrail から Athena のテーブルを作成する
CloudTrail のコンソールから イベント履歴
を開きます。イベント履歴にある Amazon Athnea で高度なクエリを実行します
をクリックします。
Athena では、クエリするデータのログフォーマットに応じたテーブルを作成する必要がありますが、CloudTrail の証跡が保存された S3 バケットを選択するだけで自動でテーブルを作成してくれます。
テーブルをパーティション化してデータをロードする
CloudTrail から Athena に連携すると以下のような DDL が実行されてテーブルが作成されます。
CREATE EXTERNAL TABLE cloudtrail_logs_table ( eventVersion STRING, userIdentity STRUCT< type: STRING, principalId: STRING, arn: STRING, accountId: STRING, invokedBy: STRING, accessKeyId: STRING, userName: STRING, sessionContext: STRUCT< attributes: STRUCT< mfaAuthenticated: STRING, creationDate: STRING>, sessionIssuer: STRUCT< type: STRING, principalId: STRING, arn: STRING, accountId: STRING, userName: STRING>>>, eventTime STRING, eventSource STRING, eventName STRING, awsRegion STRING, sourceIpAddress STRING, userAgent STRING, errorCode STRING, errorMessage STRING, requestParameters STRING, responseElements STRING, additionalEventData STRING, requestId STRING, eventId STRING, resources ARRAY<STRUCT< arn: STRING, accountId: STRING, type: STRING>>, eventType STRING, apiVersion STRING, readOnly STRING, recipientAccountId STRING, serviceEventDetails STRING, sharedEventID STRING, vpcEndpointId STRING ) COMMENT 'CloudTrail table for cloudtrail-bucket bucket' ROW FORMAT SERDE 'com.amazon.emr.hive.serde.CloudTrailSerde' STORED AS INPUTFORMAT 'com.amazon.emr.cloudtrail.CloudTrailInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat' LOCATION 's3://cloudtrail-bucket/AWSLogs/XXXXXXXXXXXX/CloudTrail/' TBLPROPERTIES ('classification'='cloudtrail')
しかし、このテーブルのままではパーティションが定義されていないので、LOCATION
に指定されている S3 バケット配下すべてをスキャンします。
Athena はスキャンしたバイト数に応じて課金されます、また、スキャン範囲が広いとクエリ結果が返るまでに時間が掛かりパフォーマンスに影響します。理由がなければパーティションを定義してスキャン範囲を狭めてクエリしましょう。
既存のテーブルを後からパーティション化することはできないので、テーブルを作り直します。別名でテーブルを作成しても良いのですが、本エントリでは削除して同名テーブルで作成し直しています。
元のテーブル作成の DDL をコピーして 47 行目の PARTITIONED
句を追記して作り直しました。本エントリでは、リージョン、年、月を定義しており、例えば ap-northeast-1 の 2020 年 3 月を対象にスキャンすることができるようになります。
CREATE EXTERNAL TABLE cloudtrail_logs_table ( eventVersion STRING, userIdentity STRUCT< type: STRING, principalId: STRING, arn: STRING, accountId: STRING, invokedBy: STRING, accessKeyId: STRING, userName: STRING, sessionContext: STRUCT< attributes: STRUCT< mfaAuthenticated: STRING, creationDate: STRING>, sessionIssuer: STRUCT< type: STRING, principalId: STRING, arn: STRING, accountId: STRING, userName: STRING>>>, eventTime STRING, eventSource STRING, eventName STRING, awsRegion STRING, sourceIpAddress STRING, userAgent STRING, errorCode STRING, errorMessage STRING, requestParameters STRING, responseElements STRING, additionalEventData STRING, requestId STRING, eventId STRING, resources ARRAY<STRUCT< arn: STRING, accountId: STRING, type: STRING>>, eventType STRING, apiVersion STRING, readOnly STRING, recipientAccountId STRING, serviceEventDetails STRING, sharedEventID STRING, vpcEndpointId STRING ) COMMENT 'CloudTrail table for cloudtrail-bucket bucket' PARTITIONED BY(region string, year string, month string) ROW FORMAT SERDE 'com.amazon.emr.hive.serde.CloudTrailSerde' STORED AS INPUTFORMAT 'com.amazon.emr.cloudtrail.CloudTrailInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat' LOCATION 's3://cloudtrail-bucket/AWSLogs/XXXXXXXXXXXX/CloudTrail/' TBLPROPERTIES ('classification'='cloudtrail')
なお、パーティションにリージョン、年、月を定義したのは、CloudTrail の証跡が格納されている S3 バケットの構成に沿っているからです。 分かりやすくフォルダ構成のように記すと以下のようになっています。
cloudtrail-bucket └──AWSLogs/ └──AWS アカウント ID └──CloudTrail └──ap-northeast-1 └──2020 └──03 └──01
LOCATION
で s3://cloudtrail-bucket/AWSLogs/XXXXXXXXXXXX/CloudTrail/
を定義しているので、配下のリージョン、年、月をパーティションを定義しました。
作成し直したテーブルを確認するとパーティション化されたことが分かります。
さいごに、定義したパーティションに沿った S3 バケットのパスを指定して Athena にデータをロードします。
ALTER TABLE cloudtrail_logs_table ADD PARTITION (region='ap-northeast-1',year='2020',month='03') location 's3://cloudtrail-bucketAWSLogs/AWS アカウント ID/CloudTrail/ap-northeast-1/2020/03';
前置きが長くなりましたが、これで準備完了です。
AWS SDK for Java V2 の利用を確認する
いよいよ AWS SDK for Java V2 の利用を確認するためにクエリします。
CloudTrail のログを確認すると userAgent に aws-sdk-java-/2
が含まれていることが分かったので、直近一ヶ月分を抽出するようにクエリしました。
SELECT * FROM cloudtrail_logs_table WHERE region='ap-northeast-1' AND year='2020' AND month='03' AND userAgent like '%aws-sdk-java/2%'
すると、今回調べた環境では S3 AccessAnalyzer で利用されていることが分かりました。
S3 AccessAnalyzer を除外すると、それ以外では利用されていないことも分かりました。
SELECT * FROM cloudtrail_logs_table WHERE region='ap-northeast-1' AND year='2020' AND month='03' AND userAgent like '%aws-sdk-java/2%' AND useridentity.username != 'AWSServiceRoleForAccessAnalyzer'
おまけ
Athena 利用の際は、クエリ結果を保存する S3 バケットを指定します。以下のようなメッセージが出力されていたら、S3 バケットを指定しましょう。
以前は Athena 側で S3 バケットを作成してくれていたのですが、現在は自分で作成する必要があります。 ところが、CloudTrail から Athena に連携すると以下の名前で S3 バケットを作成してくれたので少し驚きました。
- aws-athena-query-results-AWS アカウント ID-ap-northeast-1
おわりに
普段から CloudTrail を有効化し、S3 バケットに証跡を保存しておくと、Athena を使って調査できるのはとても有用であると思いました。
本エントリがどなたかのお役に立てれば幸いです。